home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dskut / aspisrc.zip / ASPI.C next >
C/C++ Source or Header  |  1992-01-26  |  31KB  |  1,219 lines

  1. #ident "$Id: aspi.c,v 1.1 1992/01/15 01:14:12 chris Exp $"
  2.  
  3. #include <stdio.h>
  4. #include <fcntl.h>
  5. #include <dos.h>
  6. #include <string.h>
  7. #include <malloc.h>
  8. #include <ctype.h>
  9. #include <errno.h>
  10.  
  11. /*
  12.  * $Log: aspi.c,v $
  13.  * Revision 1.1  1992/01/15  01:14:12  chris
  14.  * Initial revision
  15.  *
  16.  *
  17.  *
  18.  * chris@alderan.sdata.de
  19.  */
  20.  
  21. #define DWORD unsigned long
  22. #ifndef TAPE_ID
  23. #define TAPE_ID "0:4:0"
  24. #endif
  25.  
  26. #include "aspi.h"
  27. #include "scsi.h"
  28. #include "scsierr.h"
  29.  
  30. #ifndef CTCTRL
  31. #include "tar.h"
  32. #endif
  33.  
  34. static char *aspi_c_id = "$Id: aspi.c,v 1.1 1992/01/15 01:14:12 chris Exp $";
  35.  
  36. void aspiinit();
  37. extern int errno;
  38.  
  39.  
  40. /*
  41.  * The complete scsi address of our tape device
  42.  */
  43. int adapter_id, scsi_tape_id, lun_id;
  44.  
  45. /*
  46.  * Because all the scsi functions start with:
  47.  * SCSIfunc(adapter_id, scsi_tape_id, lun, .......)
  48.  * .. we define a macro "TARGET", so that we can write SCSIfunc(TARGET, ...);
  49.  */
  50. #define TARGET adapter_id, scsi_tape_id, lun_id
  51.  
  52. #ifndef CTCTRL
  53.  
  54. /* Flags to for use with the streamer (detected at aspiopen()) */
  55. static int aspifile, no_rewind;
  56.  
  57. /* This holds the max., and min. recordsize, the streamer can deal with */
  58. static blocklimit lim;
  59. static long recsize;    /* the record size to use */
  60. static int logrec;      /* log2(recordsize) */
  61. static long apos;       /* this holds the current archive file pointer */
  62. static int write_file_mark_on_close;
  63. static int end_of_medium;
  64. static unsigned char rsense[14]; /* array for scsi-sense-data */
  65.  
  66. /*
  67.  * The next two functions are called when you open a file.
  68.  * They check if the filename specifies the scsi-tape.
  69.  * The filenames used for that are "/dev/ct" - "rewind cartridge tape"
  70.  * and "/dev/nrct" - "no rewind cartridge tape" (no rewind on close)
  71.  * I just choose those names "/dev/ct" and "/dev/nrct" because the
  72.  * filenames are unusual to exist on a MSDOS filesystem and also because
  73.  * I'm used to them from my ix386. Anyway, there are no other dependencies
  74.  * on those names in the whole program. So, if you prefer to change the
  75.  * names to "/dev/rmt0" or whatever, just change them !
  76.  * As you can see in aspicreate() and aspiopen(), I still open a
  77.  * MSDOS-output-dummy-file. "nul:" is kind of /dev/null for MSDOS
  78.  * and I had to do this because the MSDOS code from tar still
  79.  * does some operations on this file like setmode(stream) etc. and
  80.  * I was too lazy to change the code in tar. So, with this they
  81.  * may do setmode()'s on the null-device as long as they want :-)
  82.  */
  83.  
  84.  
  85. /*
  86.  * Create an archive file
  87.  */
  88.  
  89. aspicreat(path, mode)
  90. char *path;
  91. int mode;
  92. {
  93.   end_of_medium = 0;
  94.  
  95.   if ( !strcmp(path, "/dev/ct") )  {
  96.     apos = 0l;
  97.     no_rewind = 0;
  98.     aspiinit();
  99.     write_file_mark_on_close = 1;
  100.     return (aspifile=creat("NUL", mode));
  101.   } else if ( !strcmp(path,"/dev/nrct") )  {
  102.     apos = 0l;
  103.     no_rewind = 1;
  104.     aspiinit();
  105.     write_file_mark_on_close = 1;
  106.     return (aspifile=creat("NUL", mode));
  107.   }
  108.   aspifile = -1;
  109.   return creat(path, mode);
  110. }
  111.  
  112. /*
  113.  * Open an archive file
  114.  */
  115.  
  116. aspiopen(path, oflag, mode)
  117. char *path;
  118. int oflag;
  119. int mode;
  120. {
  121.   end_of_medium = 0;
  122.  
  123.   if ( !strcmp(path, "/dev/ct") )  {
  124.     apos = 0l;
  125.     no_rewind = 0;
  126.     aspiinit();
  127.     if ( (oflag & O_WRONLY) || (oflag & O_RDWR) )
  128.       write_file_mark_on_close = 1;
  129.     else write_file_mark_on_close = 0;
  130.     return (aspifile=open("NUL", oflag, mode));
  131.   } else if ( !strcmp(path,"/dev/nrct") )  {
  132.     apos = 0l;
  133.     no_rewind = 1;
  134.     aspiinit();
  135.     if ( (oflag & O_WRONLY) || (oflag & O_RDWR) )
  136.       write_file_mark_on_close = 1;
  137.     else write_file_mark_on_close = 0;
  138.     return (aspifile=open("NUL", oflag, mode));
  139.   }
  140.   aspifile = -1;
  141.   return open(path, oflag, mode);
  142. }
  143.  
  144.  
  145. /*
  146.  * So, all the other functions now just check if (fileds == aspifile)
  147.  * and do redirect the opereation to the tape. Otherwise they just
  148.  * hand the request to the original function (e.g aspiread()->read() etc.).
  149.  */
  150.  
  151.  
  152. /*
  153.  * Read data from an archive file
  154.  */
  155.  
  156. aspiread(fileds, buf, nbyte)
  157. int fileds;
  158. char *buf;
  159. int nbyte;
  160. {
  161.   int i;
  162.   unsigned int *u;
  163.  
  164.   if ( fileds == aspifile )  {
  165.     u = ( unsigned int * ) &nbyte;    /* Hack,  I know */
  166.     if ( nbyte % ( int ) recsize )  {
  167.       ( void ) fprintf(stderr,
  168.                      "aspiread: Illegal blocklen for tape: %u\n", nbyte);
  169.       ( void ) aspiclose(fileds);
  170.       exit(EX_SYSTEM);
  171.     }
  172.     i = SCSIRead(TARGET, buf, ( long ) *u, logrec, 0, 1, rsense);
  173.     if ( i )  {  /* If any error ... */
  174.       unsigned bytes_read;
  175.  
  176.       if ( i == E$BlankCheck )  {  /* EEOM  (early end of medium) */
  177.         errno = ENOSPC;
  178.         if ( (rsense[2] & 0x40) && (rsense[0] &0x80) ) {
  179.           /* compute the number of bytes read */
  180.           bytes_read =  *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
  181.           apos += ( long ) bytes_read;
  182.           return ( int ) bytes_read;
  183.         } else return 0;
  184.       } else if ( (i==E$Medium) && (rsense[2] & 0x40) && (rsense[0] & 0x80) ) {
  185.         errno = ENOSPC;
  186.         bytes_read =  *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
  187.         apos += ( long ) bytes_read;
  188.         return ( int ) bytes_read;
  189.       } else  {
  190.         ( void ) fprintf(stderr,"aspiread: errno: %d\n", i);
  191.         ( void ) aspiclose(fileds);
  192.         exit(EX_SYSTEM);
  193.       }
  194.     }
  195.     apos += ( long ) *u;
  196.     return nbyte;
  197.   }
  198.   return read(fileds, buf, nbyte);
  199. }
  200.  
  201. /*
  202.  * Write data to an archive file
  203.  */
  204.  
  205. aspiwrite(fileds, buf, nbyte)
  206. int fileds;
  207. char *buf;
  208. int nbyte;
  209. {
  210.   int i;
  211.   unsigned int *u;
  212.  
  213.  
  214.   if ( fileds == aspifile )  {
  215.  
  216.     if ( end_of_medium )  {
  217.      /*
  218.       * This only happens when an end_of_medium condition was detected
  219.       * at the previous aspiwrite() call but all bytes were written to
  220.       * the tape anyway. In this case we don't make anymore attempts to
  221.       * write to the tape but return an ENOSPC error and set the size
  222.       * of transfered bytes to 0
  223.       */
  224.       errno = ENOSPC;
  225.       return 0;
  226.     }
  227.  
  228.     u = ( unsigned int * ) &nbyte;     /* Hack , i know */
  229.  
  230.     if ( nbyte % ( int ) recsize )  {
  231.       ( void ) fprintf(stderr,
  232.                       "aspiwrite: Illegal blocklen for tape: %u\n", nbyte);
  233.       ( void ) aspiclose(fileds);
  234.       exit(EX_SYSTEM);
  235.     }
  236.  
  237.     i = SCSIWrite(TARGET, buf, ( long ) *u, logrec, 1, rsense);
  238.  
  239.     if ( i == E$EndOfMedium )  {
  240.       unsigned int bytes_read;
  241.  
  242.       end_of_medium = 1;
  243.       if ( (rsense[0] & 0x80) && (rsense[6] || rsense[5]) )  {
  244.         /* return the real number of bytes that were written to the tape */
  245.         errno = ENOSPC;
  246.         bytes_read =  *u - ((rsense[6]+(rsense[5]<<8))<<logrec);
  247.         apos += ( long ) bytes_read;
  248.         return ( int ) bytes_read;
  249.       } else i = 0; /* do not return an error if all bytes were written */
  250.     }
  251.     if ( i )  { /* any other error we can't recover */
  252.       ( void ) fprintf(stderr,"aspiwrite: errno: %d\n", i);
  253.       ( void ) aspiclose(fileds);
  254.       exit(EX_SYSTEM);
  255.     }
  256.     apos += ( long ) *u;
  257.     return nbyte;
  258.   }
  259.   return write(fileds, buf, nbyte);
  260. }
  261.  
  262. /*
  263.  * close an archive file
  264.  */
  265.  
  266. aspiclose(fileds)
  267. int fileds;
  268. {
  269.   int i;
  270.  
  271.   if ( fileds == aspifile )  {
  272.     /* first, write a filemark ! */
  273.     if ( write_file_mark_on_close && (!end_of_medium) )
  274.       if ( (i=SCSIWriteFilemarks(TARGET, 1l, 0, 0, 0)) )
  275.         ( void ) fprintf(stderr,"aspiclose: Error writing filemark\n");
  276.     /* then rewind the tape if we have to */
  277.     if ( ! no_rewind )  {
  278.       if ( (i=SCSIRewind(TARGET, 0, 0)) )
  279.         ( void ) fprintf(stderr,"aspiclose: Error rewinding the tape\n");
  280.     } else if ( ! write_file_mark_on_close )  {
  281.      /*
  282.       * This means we've been reading an archive on a "/dev/nrct" tape.
  283.       * In this case we have seek over the filemark at the end of the
  284.       * archive.
  285.       */
  286.       if ( (i=SCSISpace(TARGET, 1, 1l, 0))  )
  287.         ( void ) fprintf(stderr,"aspiclose: Error seeking filemark\n");
  288.     }
  289.     apos = 0l;
  290.   }
  291.   return close(fileds);
  292. }
  293.  
  294. /*
  295.  * Seek on the archive file
  296.  */
  297.  
  298. long aspilseek(fileds, offset, w